package com.hhy.lombok.processor;

import com.hhy.lombok.annotation.AllArgsConstructor;
import com.hhy.lombok.utils.JCUtils;
import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.code.TypeTag;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.TreeTranslator;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.ListBuffer;


import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import java.lang.annotation.Annotation;
import java.util.Set;

import static com.hhy.lombok.utils.JCUtils.getJClassFields;
import static com.hhy.lombok.utils.JCUtils.returnNone;
import static com.hhy.lombok.utils.ProcessUtils.*;
import static com.hhy.lombok.constant.Constant.*;
import static com.sun.tools.javac.util.List.nil;

/**
 * Created with IntelliJ IDEA.
 *
 * @author hai-yang
 * @date 2022/04/20/0:53
 * @description
 */

@SupportedAnnotationTypes("com.hhy.lombok.annotation.AllArgsConstructor")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class AllArgsConstructorProcessor extends BaseProcessor {

    @Override
    public void doProcess(Element element) {
        JCTree jcTree = trees.getTree(element);
        jcTree.accept(new TreeTranslator() {
            @Override
            public void visitClassDef(JCTree.JCClassDecl jcClass) {
                treeMaker.at(jcClass.pos);
                // 添加构造参数
                if (hasAllArgsConstructor(jcClass)) {
                    jcClass.defs = jcClass.defs.append(
                            createAllArgsConstructor(jcClass)
                    );
                    log.log(jcClass, "generated all args constructor");
                }
            }
        });
    }

    /**
     * 创建全参数构造方法
     *
     * @return 全参构造方法语法树节点
     */
    private JCTree.JCMethodDecl createAllArgsConstructor(JCTree.JCClassDecl jcClass) {
        ListBuffer<JCTree.JCStatement> jcStatements = new ListBuffer<>();
        // 添加构造方法的赋值语句 " this.xxx = xxx; "
        for (JCTree.JCVariableDecl jClassField : getJClassFields(jcClass)) {
            jcStatements.append(
                    JCUtils.createAssignStatement(treeMaker, treeMaker.Ident(names.fromString(THIS)),
                            jClassField.name, treeMaker.Ident(jClassField.name))
            );
        }
        return JCUtils.createMethod(treeMaker,
                names.fromString(CONSTRUCTOR_NAME),
                treeMaker.TypeIdent(TypeTag.VOID),
                JCUtils.copyVar2Param(treeMaker, getJClassFields(jcClass)),
                nil(),
                JCUtils.createBlock(treeMaker, jcStatements.toList()),
                Flags.PUBLIC
                );
    }

    /**
     * 是否存在全参的构造方法
     *
     * @param jcClass 类的语法树节点
     * @return -1 存在 0 没有存在  pos>1 原构造pos
     */
    private static boolean hasAllArgsConstructor(JCTree.JCClassDecl jcClass) {
        for (JCTree jcTree : jcClass.defs) {
            if (jcTree.getKind().equals(JCTree.Kind.METHOD)) {
                JCTree.JCMethodDecl jcMethod = (JCTree.JCMethodDecl) jcTree;
                if (CONSTRUCTOR_NAME.equals(jcMethod.name.toString())) {
                    List<JCTree.JCVariableDecl> fields = getJClassFields(jcClass);
                    if (fields.size() == jcMethod.params.size()) {
                        for (int i = 0; i < fields.size(); i++) {
                            if (!fields.get(i).vartype.type.equals(jcMethod.params.get(i).vartype.type)) {
                                return false;
                            }
                        }
                    }
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    protected Class<? extends Annotation> getNeedToHandleAnnotation() {
        return AllArgsConstructor.class;
    }
}
